﻿using LightCAD.Core;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace LightCAD.Runtime
{
    using System.Diagnostics;
    using LightCAD.MathLib;
    using Microsoft.CodeAnalysis;

    public class PropertiesRuntime
    {
        private DocumentRuntime docRt { get; set; }
        public IPropertyControl PropertyCtrl { get; set; }

        public PropertiesRuntime(DocumentRuntime docRt, IPropertyControl control)
        {
            this.docRt = docRt;
            this.PropertyCtrl = control;

            this.docRt.Action.SelectsChanged += this.Action_SelectsChanged;
            this.docRt.UIPropertyChanged += this.UIPropertyChanged;
        }
        public  void UIPropertyChanged()
        {
            var docAction = this.docRt.Action;
            var grpEles = GroupingSelectedElements(docAction.SelectedElements);
            var eleObservers = PropertyAction.GetSharedPropertyObservers(docAction);
            var eleTypeObservers = GetElementTypeObservers(grpEles.Keys.ToList());
            var mergeAll = MergeObservers(eleTypeObservers);
            this.PropertyCtrl.PropertyChanged(
                grpEles,
                eleObservers,
                eleTypeObservers,
                mergeAll,
                (eles) =>
                {
                    this.docRt.PropertyUIChange(eles);
                    //this.docRt.Action.ClearElementGrips(eles);
                    //this.docRt.Action.ResetElementGrips(eles);
                });
        }
        private void Action_SelectsChanged(IDocumentEditor sender, SelectedEventArgs e)
        {
            var docAction = this.docRt.Action;//sender.DocRt.Action;
            Debug.Assert(docAction!= null);

            var grpEles = GroupingSelectedElements(docAction.SelectedElements);
            var eleObservers = PropertyAction.GetSharedPropertyObservers(docAction);
            var eleTypeObservers = GetElementTypeObservers(grpEles.Keys.ToList());

            var mergeAll = MergeObservers(eleTypeObservers);
            this.PropertyCtrl.SelectsChanged(
                grpEles,
                eleObservers,
                eleTypeObservers,
                mergeAll,
                (eles) =>
                    {

                        this.docRt.PropertyUIChange(eles);
                         
                    });
        }

        private Dictionary<ElementType, List<LcElement>> GroupingSelectedElements(List<LcElement> selectedEles)
        {
            return selectedEles.GroupBy(e => e.Type).ToDictionary(K => K.Key, V => V.ToList());
        }

        private Dictionary<ElementType, List<PropertyObserver>> GetElementTypeObservers(List<ElementType> eleTypes)
        {
            var observers = new Dictionary<ElementType, List<PropertyObserver>>();
            foreach (var eleType in eleTypes)
            {
                var action = LcDocument.ElementActions[eleType];
                var eleObs = (action as IPropertyObserver).GetPropertyObservers();
                observers.Add(eleType, eleObs);
            }
            return observers;
        }

        private static List<PropertyObserver> MergeObservers(Dictionary<ElementType, List<PropertyObserver>> observers)
        {
            var merged = new Dictionary<string, List<PropertyObserver>>();

            var allObservers = observers.SelectMany(p => p.Value).ToList();
            var grpObservers = allObservers.GroupBy(p => p.DisplayName).ToDictionary(K => K.Key, V => V.ToList());

            int eleTypeCount = observers.Keys.Count;

            foreach (var kvp in grpObservers)
            {
                if (kvp.Value.Count == eleTypeCount)
                {
                    merged.Add(kvp.Value.First().Name, kvp.Value);
                }
            }

            return merged.Select(P => P.Value.First()).ToList();
        }
    }
}